<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
    <meta name="description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
    <meta property="og:title" content="Flow Mapping | 3D Game Shaders For Beginners" />
    <meta property="og:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
    <meta property="og:image" content="https://i.imgur.com/brdytrF.png" />
    <meta name="twitter:title" content="Flow Mapping | 3D Game Shaders For Beginners" />
    <meta name="twitter:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
    <meta name="twitter:image" content="https://i.imgur.com/brdytrF.png" />
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="author" content="David Lettier" />
    <title>Flow Mapping | 3D Game Shaders For Beginners</title>
    <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
    </style>
    <style>
      code.sourceCode > span { display: inline-block; line-height: 1.25; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode { white-space: pre; position: relative; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      code.sourceCode { white-space: pre-wrap; }
      code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          background-color: #232629;
          color: #7a7c7d;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d;  padding-left: 4px; }
      div.sourceCode
        { color: #cfcfc2; background-color: #232629; }
      @media screen {
      code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span. { color: #cfcfc2; } /* Normal */
      code span.al { color: #95da4c; } /* Alert */
      code span.an { color: #3f8058; } /* Annotation */
      code span.at { color: #2980b9; } /* Attribute */
      code span.bn { color: #f67400; } /* BaseN */
      code span.bu { color: #7f8c8d; } /* BuiltIn */
      code span.cf { color: #fdbc4b; } /* ControlFlow */
      code span.ch { color: #3daee9; } /* Char */
      code span.cn { color: #27aeae; } /* Constant */
      code span.co { color: #7a7c7d; } /* Comment */
      code span.cv { color: #7f8c8d; } /* CommentVar */
      code span.do { color: #a43340; } /* Documentation */
      code span.dt { color: #2980b9; } /* DataType */
      code span.dv { color: #f67400; } /* DecVal */
      code span.er { color: #da4453; } /* Error */
      code span.ex { color: #0099ff; } /* Extension */
      code span.fl { color: #f67400; } /* Float */
      code span.fu { color: #8e44ad; } /* Function */
      code span.im { color: #27ae60; } /* Import */
      code span.in { color: #c45b00; } /* Information */
      code span.kw { color: #cfcfc2; } /* Keyword */
      code span.op { color: #cfcfc2; } /* Operator */
      code span.ot { color: #27ae60; } /* Other */
      code span.pp { color: #27ae60; } /* Preprocessor */
      code span.re { color: #2980b9; } /* RegionMarker */
      code span.sc { color: #3daee9; } /* SpecialChar */
      code span.ss { color: #da4453; } /* SpecialString */
      code span.st { color: #f44f4f; } /* String */
      code span.va { color: #27aeae; } /* Variable */
      code span.vs { color: #da4453; } /* VerbatimString */
      code span.wa { color: #da4453; } /* Warning */
    </style>
    <!--[if lt IE 9]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
<p><a href="foam.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="outlining.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
<h1 id="3d-game-shaders-for-beginners">3D Game Shaders For Beginners</h1>
<h2 id="flow-mapping">Flow Mapping</h2>
<p><img src="https://i.imgur.com/3WDO9xW.gif" alt="Flow Mapping" /></p>
<p>Flow mapping is useful when you need to animate some fluid material. Much like diffuse maps map UV coordinates to diffuse colors and normal maps map UV coordinates to normals, flow maps map UV coordinates to 2D translations or flows.</p>
<p><img src="https://i.imgur.com/b9Vw94N.png" alt="Flow Map" /></p>
<p>Here you see a flow map that maps UV coordinates to translations in the positive y-axis direction. Flow maps use the red and green channels to store translations in the x and y direction. The red channel is for the x-axis and the green channel is the y-axis. Both range from zero to one which translates to flows that range from <code>(-1, -1)</code> to <code>(1, 1)</code>. This flow map is all one color consisting of 0.5 red and 0.6 green.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a>[r, g, b] =</span>
<span id="cb1-2"><a href="#cb1-2"></a>  [r * <span class="dv">2</span> - <span class="dv">1</span>, g * <span class="dv">2</span> - <span class="dv">1</span>, b * <span class="dv">2</span> - <span class="dv">1</span>] =</span>
<span id="cb1-3"><a href="#cb1-3"></a>    [ x, y, z]</span></code></pre></div>
<p>Recall how the colors in a normal map are converted to actual normals. There is a similar process for flow maps.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="co">// ...</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a>uniform sampler2D flowTexture;</span>
<span id="cb2-4"><a href="#cb2-4"></a></span>
<span id="cb2-5"><a href="#cb2-5"></a>  vec2 flow = texture(flowTexture, uv).xy;</span>
<span id="cb2-6"><a href="#cb2-6"></a>       flow = (flow - <span class="fl">0.5</span>) * <span class="dv">2</span>;</span>
<span id="cb2-7"><a href="#cb2-7"></a></span>
<span id="cb2-8"><a href="#cb2-8"></a>  <span class="co">// ...</span></span></code></pre></div>
<p>To convert a flow map color to a flow, you minus 0.5 from the channel (red and green) and multiply by two.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a>(r, g) =</span>
<span id="cb3-2"><a href="#cb3-2"></a> ( (r - <span class="fl">0.5</span>) * <span class="dv">2</span></span>
<span id="cb3-3"><a href="#cb3-3"></a> , (g - <span class="fl">0.5</span>) * <span class="dv">2</span></span>
<span id="cb3-4"><a href="#cb3-4"></a> ) =</span>
<span id="cb3-5"><a href="#cb3-5"></a>  ( (<span class="fl">0.5</span> - <span class="fl">0.5</span>) * <span class="dv">2</span></span>
<span id="cb3-6"><a href="#cb3-6"></a>  , (<span class="fl">0.6</span> - <span class="fl">0.5</span>) * <span class="dv">2</span></span>
<span id="cb3-7"><a href="#cb3-7"></a>  ) =</span>
<span id="cb3-8"><a href="#cb3-8"></a>    (x, y) =</span>
<span id="cb3-9"><a href="#cb3-9"></a>      (<span class="dv">0</span>, <span class="fl">0.2</span>)</span></code></pre></div>
<p>The flow map above maps each UV coordinate to the flow <code>(0, 0.2)</code>. This indicates zero movement in the x direction and a movement of 0.2 in the y direction.</p>
<p>The flows can be used to translate all sorts of things but they're typically used to offset the UV coordinates of a another texture.</p>
<p><img src="https://i.imgur.com/N6TWBw8.gif" alt="Foam Mask" /></p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a>  <span class="co">// ...</span></span>
<span id="cb4-2"><a href="#cb4-2"></a></span>
<span id="cb4-3"><a href="#cb4-3"></a>  vec2 flow = texture(flowTexture, diffuseCoord).xy;</span>
<span id="cb4-4"><a href="#cb4-4"></a>       flow = (flow - <span class="fl">0.5</span>) * <span class="dv">2</span>;</span>
<span id="cb4-5"><a href="#cb4-5"></a></span>
<span id="cb4-6"><a href="#cb4-6"></a>  vec4 foamPattern =</span>
<span id="cb4-7"><a href="#cb4-7"></a>    texture</span>
<span id="cb4-8"><a href="#cb4-8"></a>      ( foamPatternTexture</span>
<span id="cb4-9"><a href="#cb4-9"></a>      , vec2</span>
<span id="cb4-10"><a href="#cb4-10"></a>          ( diffuseCoord.x + flow.x * osg_FrameTime</span>
<span id="cb4-11"><a href="#cb4-11"></a>          , diffuseCoord.y + flow.y * osg_FrameTime</span>
<span id="cb4-12"><a href="#cb4-12"></a>          )</span>
<span id="cb4-13"><a href="#cb4-13"></a>      );</span>
<span id="cb4-14"><a href="#cb4-14"></a></span>
<span id="cb4-15"><a href="#cb4-15"></a>  <span class="co">// ...</span></span></code></pre></div>
<p>For example, the demo program uses a flow map to animate the water. Here you see the flow map being used to animate the <a href="foam.html#mask">foam mask</a>. This continuously moves the diffuse UV coordinates directly up, giving the foam mask the appearance of moving down stream.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1"></a>          <span class="co">// ...</span></span>
<span id="cb5-2"><a href="#cb5-2"></a></span>
<span id="cb5-3"><a href="#cb5-3"></a>          ( diffuseCoord.x + flow.x * osg_FrameTime</span>
<span id="cb5-4"><a href="#cb5-4"></a>          , diffuseCoord.y + flow.y * osg_FrameTime</span>
<span id="cb5-5"><a href="#cb5-5"></a></span>
<span id="cb5-6"><a href="#cb5-6"></a>          <span class="co">// ...</span></span></code></pre></div>
<p>You'll need how many seconds have passed since the first frame in order to animate the UV coordinates in the direction indicated by the flow. <code>osg_FrameTime</code> is <a href="https://github.com/panda3d/panda3d/blob/daa57733cb9b4ccdb23e28153585e8e20b5ccdb5/panda/src/display/graphicsStateGuardian.cxx#L930">provided</a> by Panda3D. It is a timestamp of how many seconds have passed since the first frame.</p>
<h3 id="source">Source</h3>
<ul>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/src/main.cxx" target="_blank" rel="noopener noreferrer">main.cxx</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/vertex/base.vert" target="_blank" rel="noopener noreferrer">base.vert</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/vertex/basic.vert" target="_blank" rel="noopener noreferrer">basic.vert</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/normal.frag" target="_blank" rel="noopener noreferrer">normal.frag</a></li>
</ul>
<h2 id="copyright">Copyright</h2>
<p>(C) 2019 David Lettier <br> <a href="https://www.lettier.com">lettier.com</a></p>
<p><a href="foam.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="outlining.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
  </body>
</html>
